home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  47.5 KB  |  2,013 lines

  1. /* Panel managing.
  2.    Copyright (C) 1994, 1995 Miguel de Icaza.
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <config.h>
  19. #include "tty.h"
  20. #include "fs.h"
  21. #include <sys/param.h>
  22. #include <string.h>
  23. #include <stdlib.h>    /* For malloc() and free() */
  24. #include <stdio.h>
  25. #include <errno.h>
  26. #ifdef HAVE_UNISTD_H
  27. #   include <unistd.h>    /* For chdir(), readlink() and getwd()/getcwd() */
  28. #endif
  29. #include "mem.h"
  30. #include "mad.h"
  31. #include "global.h"
  32. #include "dir.h"
  33. #include "util.h"
  34. #include "panel.h"
  35. #include "color.h"
  36. #include "tree.h"
  37. #include "win.h"
  38. #include "main.h"
  39. #include "ext.h"        /* regexp_command */
  40. #include "mouse.h"        /* For Gpm_Event */
  41. #include "cons.saver.h"        /* For console_flag */
  42. #include "layout.h"        /* Most layout variables are here */
  43. #include "dialog.h"        /* for message (...) */
  44. #include "cmd.h"
  45. #include "key.h"        /* XCTRL and ALT macros  */
  46. #include "setup.h"        /* For loading/saving panel options */
  47. #include "user.h"
  48. #include "profile.h"
  49. #include "widget.h"
  50. #include "../vfs/vfs.h"
  51. #include "../vfs/extfs.h"
  52.  
  53. /* "$Id: screen.c,v 1.19 1995/02/21 19:07:10 miguel Exp $" */
  54.  
  55. #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
  56.  
  57. /* If true, show the mini-info on the panel */
  58. int show_mini_info = 1;
  59.  
  60. /* If true, then use stat() on the cwd to determine directory changes */
  61. int fast_reload = 0;
  62.  
  63. /* If true, use some usability hacks by Torben */
  64. int torben_fj_mode = 0;
  65.  
  66. /* If true, up/down keys scroll the pane listing by pages */
  67. int panel_scroll_pages = 1;
  68.  
  69. /* If we have an info panel, this points to it */
  70. WPanel *the_info_panel = 0;
  71.  
  72. /* The hook list for the select file function */
  73. Hook *select_file_hook = 0;
  74.  
  75. #ifndef HAVE_TK
  76. #   define x_adjust_top_file(p)
  77. #endif
  78.  
  79. #ifdef HAVE_X
  80. #   define set_colors(x)
  81. #else
  82. #   define x_create_panel(x,y,z) 1;
  83. #   define x_panel_load_index(p,x)
  84.  
  85. void set_colors (WPanel *panel)
  86. {
  87.     standend ();
  88.     if (hascolors)
  89.     attrset (NORMAL_COLOR);
  90. }
  91.  
  92. void set_attr (int hilight, int marked)
  93. {
  94.     int color;
  95.  
  96.     color = (marked * 2 + hilight);
  97.     standend ();
  98.  
  99.     /* Does this work on B&W terminals? */
  100.     if (hascolors){
  101.     attrset (sel_mark_color [color]);
  102.     } else {
  103.     if (hilight)
  104.         attrset (A_REVERSE | (marked ? A_BOLD : 0));
  105.     else
  106.         if (marked)
  107.         attrset (A_BOLD);
  108.     }
  109. }
  110. #endif
  111.  
  112. /* This functions return a string representation of a file entry */
  113. char *string_file_type (file_entry *fe, int len)
  114. {
  115.     static char buffer [2];
  116.  
  117.     if (S_ISDIR (fe->buf.st_mode))
  118.     buffer [0] = PATH_SEP;
  119.     else if (S_ISLNK (fe->buf.st_mode)) {
  120.         if (fe->f.link_to_dir)
  121.             buffer [0] = '~';
  122.         else if (fe->f.stalled_link)
  123.             buffer [0] = '!';
  124.         else
  125.         buffer [0] = '@';
  126.     } else if (S_ISSOCK (fe->buf.st_mode))
  127.     buffer [0] = '=';
  128.     else if (S_ISCHR (fe->buf.st_mode))
  129.     buffer [0] = '-';
  130.     else if (S_ISBLK (fe->buf.st_mode))
  131.     buffer [0] = '+';
  132.     else if (S_ISFIFO (fe->buf.st_mode))
  133.     buffer [0] = '|';
  134.     else if (is_exe (fe->buf.st_mode))
  135.     buffer [0] = '*';
  136.     else
  137.     buffer [0] = ' ';
  138.     buffer [1] = 0;
  139.     return buffer;
  140. }
  141.  
  142. char *string_file_permission (file_entry *fe, int len)
  143. {
  144.     return string_perm (fe->buf.st_mode);
  145. }
  146.  
  147. char *string_file_nlinks (file_entry *fe, int len)
  148. {
  149.     static char buffer [16];
  150.  
  151.     sprintf (buffer, "%16d", fe->buf.st_nlink);
  152.     return buffer;
  153. }
  154.  
  155. char *string_file_owner (file_entry *fe, int len)
  156. {
  157.     return get_owner (fe->buf.st_uid);
  158. }
  159.  
  160. char *string_file_group (file_entry *fe, int len)
  161. {
  162.     return get_group (fe->buf.st_gid);
  163. }
  164.  
  165. char *string_file_size (file_entry *fe, int len)
  166. {
  167.     static char buffer [16];
  168.     int i;
  169.  
  170. #ifdef HAVE_ST_RDEV
  171.     if (S_ISBLK (fe->buf.st_mode) || S_ISCHR (fe->buf.st_mode))
  172.         sprintf (buffer, "%3d,%3d", (int) (fe->buf.st_rdev >> 8), 
  173.             (int) (fe->buf.st_rdev & 0xff));
  174.     else
  175. #endif 
  176.     {   
  177.         sprintf (buffer, "%d", (int) fe->buf.st_size);
  178.         if (len && (i = strlen (buffer)) > len) {
  179.             if (i - 2 > len) {
  180.                 if (i - 5 > len)
  181.                     sprintf (buffer, "%dG", (int) ((fe->buf.st_size) >> 30));
  182.                 else
  183.                     sprintf (buffer, "%dM", (int) ((fe->buf.st_size) >> 20));
  184.             } else
  185.                 sprintf (buffer, "%dK", (int) ((fe->buf.st_size) >> 10));
  186.         }
  187.     }
  188.     return buffer;
  189. }
  190.  
  191. char *string_file_mtime (file_entry *fe, int len)
  192. {
  193.     return file_date (fe->buf.st_mtime);
  194. }
  195.  
  196. char *string_file_atime (file_entry *fe, int len)
  197. {
  198.     return file_date (fe->buf.st_atime);
  199. }
  200.  
  201. char *string_file_ctime (file_entry *fe, int len)
  202. {
  203.     return file_date (fe->buf.st_ctime);
  204. }
  205.  
  206. char *string_file_name (file_entry *fe, int len)
  207. {
  208.     if (len)
  209.         return name_trunc (fe->fname, len);
  210.     else
  211.     return fe->fname;
  212. }
  213.  
  214. char *string_space (file_entry *fe, int len)
  215. {
  216.     return " ";
  217. }
  218.  
  219. char *string_marked (file_entry *fe, int len)
  220. {
  221.     return fe->f.marked ? "*" : " ";
  222. }
  223.  
  224. char *string_file_perm_octal (file_entry *fe, int len)
  225. {
  226.     static char buffer [9];
  227.  
  228.     sprintf (buffer, "0%06o", fe->buf.st_mode);
  229.     return buffer;
  230. }
  231.  
  232. char *string_inode (file_entry *fe, int len)
  233. {
  234.     static char buffer [9];
  235.  
  236.     sprintf (buffer, "%ld", fe->buf.st_ino);
  237.     return buffer;
  238. }
  239.  
  240. char *string_file_ngid (file_entry *fe, int len)
  241. {
  242.     static char buffer [9];
  243.  
  244.     sprintf (buffer, "%d", fe->buf.st_gid);
  245.     return buffer;
  246. }
  247.  
  248. char *string_file_nuid (file_entry *fe, int len)
  249. {
  250.     static char buffer [9];
  251.  
  252.     sprintf (buffer, "%d", fe->buf.st_uid);
  253.     return buffer;
  254. }
  255.  
  256. static struct {
  257.     char *id;
  258.     int  min_size;
  259.     int  expands;
  260.     int  default_just;
  261.     char *title;
  262.     char *(*string_fn)(file_entry *, int);
  263. } formats [] = {
  264. { "name",  12, 1, J_LEFT,  "Name",       string_file_name },
  265. { "size",  7,  0, J_RIGHT, "Size",       string_file_size },
  266. { "type",  1,  0, J_LEFT,  "",           string_file_type },
  267. { "mtime", 12, 0, J_RIGHT, "MTime",      string_file_mtime },
  268. { "perm",  10, 0, J_RIGHT, "Permission", string_file_permission },
  269. { "mode",  7,  0, J_RIGHT, "OctM",       string_file_perm_octal },
  270. { "|",     1,  0, J_RIGHT, "|",          0 },
  271. { "nlink", 2,  0, J_RIGHT, "Nl",         string_file_nlinks },
  272. { "ngid",  5,  0, J_RIGHT, "GID",        string_file_ngid },
  273. { "nuid",  5,  0, J_RIGHT, "UID",        string_file_nuid },
  274. { "owner", 8,  0, J_LEFT,  "Owner",      string_file_owner },
  275. { "group", 8,  0, J_LEFT,  "Group",      string_file_group },
  276. { "atime", 12, 0, J_RIGHT, "ATime",      string_file_atime },
  277. { "ctime", 12, 0, J_RIGHT, "CTime",      string_file_ctime },
  278. { "space", 1,  0, J_RIGHT, " ",          string_space },
  279. { "mark",  1,  0, J_RIGHT, " ",          string_marked },
  280. { "inode", 5,  0, J_RIGHT, "Inode",      string_inode },
  281. };
  282.  
  283. static char *
  284. to_buffer (char *dest, int just_mode, int len, char *txt)
  285. {
  286.     int txtlen = strlen (txt);
  287.     int still;
  288.  
  289.     if (txtlen > len){
  290.     if (just_mode != J_LEFT)
  291.         txt += txtlen - len;
  292.     txtlen = len;
  293.     }
  294.     still = len - txtlen;
  295.     if (just_mode == J_LEFT){
  296.     strcpy (dest, txt);
  297.     dest += txtlen;
  298.     while (still--)
  299.         *dest++ = ' ';
  300.     *dest = 0;
  301.     } else {
  302.     while (still--)
  303.         *dest++ = ' ';
  304.     strcpy (dest, txt);
  305.     dest += txtlen;
  306.     }
  307.     return dest;
  308. }
  309.  
  310. /* Formats the file number file_index of panel in the buffer dest */
  311. void format_file (char *dest, WPanel *panel, int file_index, int width)
  312. {
  313.     int   i, length = 0;
  314.     int   top = panel->fmt_count;
  315.     char  *txt;
  316.     char  *old_pos;
  317.     char  *cdest = dest;
  318.     int   just_mode; 
  319.     int   empty_line = file_index >= panel->count;
  320.    
  321.     for (i = 0; i < top; i++){
  322.     file_entry *fe = &panel->dir.list [file_index];
  323.  
  324.     if (panel->format [i].string_fn){
  325.         if (empty_line)
  326.         txt = " ";
  327.         else
  328.         txt = (*panel->format [i].string_fn)(fe, panel->format [i].field_len);
  329.         just_mode = panel->format [i].just_mode;
  330.  
  331.         old_pos = cdest;
  332.         cdest = to_buffer (cdest, just_mode, panel->format [i].field_len, txt);
  333.         length += panel->format [i].field_len;
  334. #ifndef HAVE_X
  335.         addstr (old_pos);
  336. #endif
  337.     } else {
  338. #ifndef HAVE_X
  339.         one_vline ();
  340. #else
  341.         *cdest++ = ' ';
  342. #endif
  343.         length++;
  344.     }
  345.     }
  346.     if (length < width){
  347.     int still = width - length;
  348.     while (still--)
  349. #ifdef HAVE_X
  350.         *cdest++ = ' ';
  351.     *cdest = 0;
  352. #else
  353.         addch (' ');
  354. #endif
  355.     }
  356. }
  357.  
  358. #ifndef HAVE_X
  359. void repaint_file (WPanel *panel, int file_index, int mv)
  360. {
  361.     int    second_column = 0;
  362.     int       width, offset;
  363.     char   buffer [255];
  364.  
  365.     offset = 0;
  366.     if (panel->split){
  367.     
  368.     second_column = (file_index - panel->top_file) / llines (panel);
  369.     width = (panel->widget.cols/2 - 2) - 1;
  370.     
  371.     if (second_column){
  372.         offset = 2 + width;
  373.         width = (panel->widget.cols-2) - (panel->widget.cols-2)/2 - 1;
  374.     } 
  375.     } else
  376.         width = (panel->widget.cols - 2);
  377.  
  378.     if (mv){
  379.     if (panel->split){
  380.         widget_move (&panel->widget,
  381.              (file_index - panel->top_file) %
  382.              llines (panel) + 2,
  383.              (offset + 1));
  384.     } else
  385.         widget_move (&panel->widget, file_index - panel->top_file + 2, 1);
  386.     }
  387.     
  388.     format_file (buffer, panel, file_index, width);
  389.     
  390.     if (panel->split){
  391.     if (second_column)
  392.         addch (' ');
  393.     else {
  394.         attrset (NORMAL_COLOR);
  395.         one_vline ();
  396.     }
  397.     }
  398. }
  399. #endif
  400.  
  401. /* FIXME: This function uses hard coded constants */
  402. /* panel->cols - 22 is not a wise idea */
  403. void mini_info_brief (WPanel *panel)
  404. {
  405.     int   isdir = 0;
  406.     char  *sdir_txt = "";
  407.     
  408. #define entry (panel->dir.list [panel->selected].buf)
  409.     
  410.     if (S_ISDIR (entry.st_mode)){
  411.     isdir = 1;
  412.     sdir_txt = strcmp (panel->dir.list [panel->selected].fname, "..")
  413.         ? ">SUB-DIR<" : ">UP--DIR<";
  414.     }
  415.  
  416.     printw ("%s%-*s", string_file_type (&panel->dir.list [panel->selected], 1),
  417.          panel->widget.cols-24, split_extension
  418.          (name_trunc (panel->dir.list [panel->selected].fname,
  419.               panel->widget.cols-24), panel->widget.cols-24));
  420.  
  421.     one_vline ();
  422.     printw ("%*s", 7, isdir ? sdir_txt : size_trunc (entry.st_size));
  423.     one_vline ();
  424.  
  425.     printw ("%10s", string_perm (entry.st_mode));
  426. }
  427.  
  428. void display_mini_info (WPanel *panel)
  429. {
  430. #ifndef HAVE_X
  431.     if (!show_mini_info)
  432.     return;
  433.     
  434.     widget_move (&panel->widget, llines (panel)+3, 1);
  435.     
  436.     if (panel->searching){
  437.     attrset (INPUT_COLOR);
  438.     printw ("/%-*s", panel->widget.cols-3, panel->search_buffer);
  439.     attrset (NORMAL_COLOR);
  440.     return;
  441.     }
  442.  
  443. #if 0
  444.     if (panel->view_type == view_tree){
  445.     attrset (NORMAL_COLOR);
  446.     printw  ("%-*s", panel->widget.cols-2,
  447.          name_trunc (panel->cwd, panel->widget.cols));
  448.     return;
  449.     }
  450. #endif
  451.     
  452.     if (panel->marked){
  453.     char buffer [100];
  454.     char *p;
  455.     
  456.     attrset (MARKED_COLOR);
  457.     printw  ("%*s", panel->widget.cols-2, " ");
  458.     widget_move (&panel->widget, llines (panel)+3, 1);
  459.     sprintf (buffer, "  %s bytes in %d file%s",
  460.          size_trunc_sep (panel->total), panel->marked,
  461.          panel->marked == 1 ? "" : "s");
  462.     p = buffer;
  463.     if (strlen (buffer) > panel->widget.cols-4){
  464.         buffer [panel->widget.cols-4] = 0;
  465.         p += 2;
  466.     }
  467.     printw ("%-*s", panel->widget.cols-2, p);
  468.     return;
  469.     }
  470.  
  471.     set_colors (panel);
  472. #ifndef _OS_NT    
  473.     if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
  474.     char *link, link_target [MC_MAXPATHLEN];
  475.     int  len;
  476.  
  477.     link = copy_strings (panel->cwd, PATH_SEP_STR,
  478.                  panel->dir.list [panel->selected].fname, 0);
  479.     len = mc_readlink (link, link_target, MC_MAXPATHLEN);
  480.     free (link);
  481.     if (len > 0){
  482.         link_target[len] = 0;
  483.         printw ("-> %-*s", panel->widget.cols - 5,
  484.              name_trunc (link_target, panel->widget.cols - 5));
  485.     } else 
  486.         addstr ("<readlink failed>");
  487.     return;
  488.     }
  489. #endif
  490.     if (panel->user_mini_status){
  491.     char *err;
  492.  
  493.     if (panel->format)
  494.         free (panel->format);
  495.     panel->format = parse_display_format (panel, panel->mini_status_format,
  496.                           &err, 1);
  497.     if (err){
  498.         beep ();    /* For debugging */
  499.         free (panel->mini_status_format);
  500.         panel->mini_status_format = strdup (DEFAULT_USER_FORMAT);
  501.         panel->format =
  502.         parse_display_format (panel, panel->mini_status_format,
  503.                       &err, 1);
  504.     }
  505. #ifndef HAVE_XVIEW    
  506.     repaint_file (panel, panel->selected, 0);
  507. #endif    
  508.     
  509.     /* This clears the second half of the mini status line, 'cause
  510.        repaint_file writes only the first half */
  511.     if (panel->split){
  512.         widget_move (&panel->widget, llines (panel)+3,
  513.              (panel->widget.cols-2)/2);
  514.         printw ("%*s", (panel->widget.cols-2) -
  515.             (panel->widget.cols-2)/2 + 1, "");
  516.     }
  517.     
  518.     if (panel->format)
  519.         free (panel->format);
  520.     panel->format = parse_display_format (panel, panel_format (panel),
  521.                           &err, 0);
  522.     return;
  523.     }
  524.  
  525.     if (panel->list_type == list_brief){
  526.     mini_info_brief (panel);
  527.     return;
  528.     }
  529.     
  530.     printw ("%-*s", panel->widget.cols-2,
  531.         name_trunc(panel->dir.list [panel->selected].fname,
  532.                panel->widget.cols-2));
  533. #endif
  534. }
  535.  
  536. #ifndef HAVE_XVIEW
  537. void paint_dir (WPanel *panel)
  538. {
  539.     int i;
  540.     int hilight;        /* Color used for hilighting */
  541.     int marked;            /* Color used for marked file */
  542.     int items;            /* Number of items */
  543.  
  544.     items = llines (panel) * (panel->split ? 2 : 1);
  545.     
  546.     for (i = 0; i < items; i++){
  547.     if (i+panel->top_file >= panel->count)
  548.         set_attr (0, 0);
  549.     else {
  550.         hilight = panel->selected==i+panel->top_file && panel->active;
  551.         marked  = panel->dir.list [i+panel->top_file].f.marked;
  552.         set_attr (hilight, marked);
  553.     }
  554.     repaint_file (panel, i+panel->top_file, 1);
  555.     }
  556.     standend ();
  557.     panel->dirty = 0;
  558. }
  559. #endif
  560.  
  561. #ifdef HAVE_X
  562. #define mini_info_separator(x)
  563. #else
  564. static void mini_info_separator (WPanel *panel)
  565. {
  566.     if (!show_mini_info)
  567.     return;
  568.     
  569.     standend ();
  570.     widget_move (&panel->widget, llines (panel)+2, 1);
  571. #ifdef HAVE_SLANG
  572.     attrset (NORMAL_COLOR);
  573.     hline (ACS_HLINE, panel->widget.cols-2);
  574. #else
  575.     hline ((slow_terminal ? '-' : ACS_HLINE) | NORMAL_COLOR,
  576.       panel->widget.cols-2);
  577. #endif 
  578. }
  579.  
  580. void show_dir (WPanel *panel)
  581. {
  582.     char tmp [200];
  583.  
  584.     set_colors (panel);
  585.     draw_double_box (panel->widget.parent,
  586.                 panel->widget.y,    panel->widget.x,
  587.                 panel->widget.lines, panel->widget.cols);
  588.  
  589. #ifdef HAVE_SLANG                
  590.     if (show_mini_info) {
  591. #ifdef linux_unicode
  592.         if (SLtt_Unicode) {
  593.             SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2, 
  594.                 panel->widget.x, SLUNI_DSLTEE_CHAR);
  595.             SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2, 
  596.                 panel->widget.x + panel->widget.cols - 1, SLUNI_DSRTEE_CHAR);
  597.         } else
  598. #endif /* linux_unicode */
  599.     {
  600.             SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
  601.                 panel->widget.x, SLSMG_LTEE_CHAR);
  602.             SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
  603.                 panel->widget.x + panel->widget.cols - 1, SLSMG_RTEE_CHAR);
  604.         }
  605.     }
  606. #endif /* have_slang */
  607.     
  608.     if (panel->active)
  609.     attrset (REVERSE_COLOR);
  610.  
  611.     widget_move (&panel->widget, 0, 1);
  612.  
  613.     trim (strip_home (panel->cwd), tmp, panel->widget.cols-5);
  614.     addstr (tmp);
  615.     
  616.     if (panel->active)
  617.     standend ();
  618. }
  619. #endif
  620.  
  621. /* To be used only by long_frame and full_frame to adjust top_file */
  622. static void adjust_top_file (WPanel *panel)
  623. {
  624.     int old_top = panel->top_file;
  625.     
  626.     if (panel->selected - old_top > llines (panel))
  627.     panel->top_file = panel->selected;
  628.     if (old_top - panel->count > llines (panel))
  629.     panel->top_file = panel->count - llines (panel);
  630.  
  631. #ifdef HAVE_TK
  632.     if (old_top != panel->top_file)
  633.     x_adjust_top_file (panel);
  634. #endif
  635. }
  636.  
  637. extern void paint_info_panel (WPanel *panel);
  638.  
  639. /* Repaints the information that changes after a command */
  640. void panel_update_contents (WPanel *panel)
  641. {
  642.     show_dir (panel);
  643. #ifdef HAVE_X
  644.     x_fill_panel (panel);
  645. #else
  646.     paint_dir (panel);
  647. #endif
  648.     display_mini_info (panel);
  649. }
  650.  
  651. void paint_panel (WPanel *panel)
  652. {
  653.     paint_frame (panel);
  654.     panel_update_contents (panel);
  655.     mini_info_separator (panel);
  656. }
  657.  
  658. void Xtry_to_select (WPanel *panel, char *name)
  659. {
  660.     int i;
  661.     char *subdir;
  662.     
  663.     if (!name){
  664.     panel->selected = 0;
  665.     panel->top_file = 0;
  666.     x_adjust_top_file (panel);
  667.     return;
  668.     }
  669.  
  670.     /* We only want the last component of the directory */
  671.     for (subdir = name + strlen (name) - 1; subdir >= name; subdir--){
  672.     if (*subdir == PATH_SEP){
  673.         subdir++;
  674.         break;
  675.     }
  676.     }
  677.     if (subdir < name)
  678.     subdir = name;
  679.     
  680.     /* Search that subdirectory, if found select it */
  681.     for (i = 0; i < panel->count; i++){
  682.     if (strcmp (subdir, panel->dir.list [i].fname))
  683.         continue;
  684.  
  685.     if (i != panel->selected){
  686.         panel->selected = i;
  687.         panel->top_file = panel->selected - (panel->widget.lines-2)/2;
  688.         if (panel->top_file < 0)
  689.         panel->top_file = 0;
  690.         x_adjust_top_file (panel);
  691.     }
  692.     return;
  693.     }
  694.  
  695.     /* Try to select a file near the file that is missing */
  696.     if (panel->selected >= panel->count){
  697.     panel->selected = panel->count-1;
  698.     panel->top_file = panel->selected - (panel->widget.lines)/2;
  699.     if (panel->top_file < 0)
  700.         panel->top_file = 0;
  701.     x_adjust_top_file (panel);
  702.     } else
  703.     return;
  704. }
  705.  
  706. /* Sets the cols variable in the widget structure according to the
  707.  * settings selected by the user
  708.  */
  709. void panel_update_cols (Widget *widget, int frame_size)
  710. {
  711.     int cols, origin;
  712.     
  713.     if (horizontal_split){
  714.     widget->cols = COLS;
  715.     return;
  716.     }
  717.  
  718.     if (frame_size == frame_full){
  719.     cols = COLS;
  720.     origin = 0;
  721.     } else {
  722.     if (widget == get_panel_widget (0)){
  723.         cols   = first_panel_size;
  724.         origin = 0;
  725.     } else {
  726.         cols   = COLS-first_panel_size;
  727.         origin = first_panel_size;
  728.     }
  729.     }
  730.     
  731.     widget->cols = cols;
  732.     widget->x = origin;
  733. }
  734.  
  735. int panel_callback (Dlg_head *h, WPanel *p, int Msg, int Par);
  736. int panel_event    (Gpm_Event *event, WPanel *panel);
  737.  
  738. static char *panel_save_name (WPanel *panel)
  739. {
  740.     extern int saving_setup;
  741.     
  742.     /* If the program is shuting down */
  743.     if ((midnight_shutdown && auto_save_setup) || saving_setup)
  744.     return copy_strings (panel->panel_name, 0);
  745.     else
  746.     return copy_strings ("Temporal:", panel->panel_name, 0);
  747. }
  748.  
  749. static void panel_destroy (WPanel *p)
  750. {
  751.     char *name = panel_save_name (p);
  752.  
  753.     panel_save_setup (p, name);
  754.     clean_dir (&p->dir, p->count);
  755.  
  756.     free (p->user_format);
  757.     free (p->mini_status_format);
  758.     free (p->format);
  759.     free (p->dir.list);
  760.     free (p->panel_name);
  761.     free (name);
  762. }
  763.  
  764. void panel_update_format (WPanel *panel)
  765. {
  766.     char *err;
  767.     
  768.     panel->format = parse_display_format (panel, panel_format (panel),
  769.                       &err, 0);
  770.     if (err)
  771.     free (err);
  772.     panel_update_cols (&(panel->widget), panel->frame_size);
  773. }
  774.  
  775. /* Panel creation */
  776. /* The parameter specifies the name of the panel for setup retieving */
  777. WPanel *panel_new (char *panel_name)
  778. {
  779.     WPanel *panel;
  780.     char *section;
  781.  
  782.     panel = xmalloc (sizeof (WPanel), "panel_new");
  783.  
  784.     /* No know sizes of the panel at startup */
  785.     init_widget (&panel->widget, 0, 0, 0, 0, (callback_fn)
  786.          panel_callback, (destroy_fn) panel_destroy,
  787.          (mouse_h) panel_event);
  788.  
  789.     /* We do not want the cursor */
  790.     widget_want_cursor (panel->widget, 0);
  791.     
  792.     mc_get_current_wd (panel->cwd, sizeof (panel->cwd)-2);
  793.     strcpy (panel->lwd, ".");
  794.  
  795.     panel->dir.list  = (file_entry *) malloc (MIN_FILES * sizeof (file_entry));
  796.     panel->dir.size  = MIN_FILES;
  797.     panel->active    = 0;
  798.     panel->filter    = 0;
  799.     panel->split     = 0;
  800.     panel->top_file  = 0;
  801.     panel->selected  = 0;
  802.     panel->marked    = 0;
  803.     panel->total     = 0;
  804.     panel->reverse   = 0;
  805.     panel->format    = 0;
  806.     panel->fmt_count = 0;
  807.     panel->dirty     = 1;
  808.     panel->has_dir_sizes = 0;
  809.     panel->dirs_marked = 0;
  810.     panel->is_panelized = 0;
  811.     panel->searching = 0;
  812.     panel->panel_name = strdup (panel_name);
  813.     panel->user_format = strdup (DEFAULT_USER_FORMAT);
  814.     panel->mini_status_format = strdup (DEFAULT_USER_FORMAT);
  815.     panel->search_buffer [0] = 0;
  816.     panel->frame_size = frame_half;
  817.     section = copy_strings ("Temporal:", panel->panel_name, 0);
  818.     if (!profile_has_section (section, profile_name)){
  819.     free (section);
  820.     section = strdup (panel->panel_name);
  821.     }
  822.     panel_load_setup (panel, section);
  823.     free (section);
  824.     
  825.     /* Load the default format */
  826.     
  827.     panel->count = do_load_dir (&panel->dir, panel->sort_type,
  828.                 panel->reverse, panel->case_sensitive, panel->filter);
  829.     return panel;
  830. }
  831.  
  832. void panel_reload (WPanel *panel)
  833. {
  834.     int i;
  835.     struct stat current_stat;
  836.  
  837. #if 0
  838.     if (!PANEL_ISVIEW (panel))
  839.     return;
  840.     
  841.     if (panel->view_type == view_tree){
  842.     tree_rescan_cmd ();
  843.     paint_panel (panel);
  844.     return;
  845.     }
  846. #endif
  847.     
  848.     if (fast_reload
  849.     && !stat (panel->cwd, ¤t_stat)
  850.     && current_stat.st_ctime == panel->dir_stat.st_ctime
  851.     && current_stat.st_mtime == panel->dir_stat.st_mtime)
  852.     return;
  853.  
  854.     while (mc_chdir (panel->cwd) == -1){
  855.     char *last_slash;
  856.  
  857.     if (panel->cwd [0] == PATH_SEP && panel->cwd [1] == 0){
  858.         panel->count = set_zero_dir (&panel->dir);
  859.         return;
  860.     }
  861.     last_slash = strrchr (panel->cwd, PATH_SEP);
  862.     if (!last_slash || last_slash == panel->cwd)
  863.         strcpy (panel->cwd, PATH_SEP_STR);
  864.     else
  865.         *last_slash = 0;
  866.         bzero (&(panel->dir_stat), sizeof (panel->dir_stat));
  867.     show_dir (panel);
  868.     }
  869.     
  870.     panel->count = do_reload_dir (&panel->dir, panel->sort_type, panel->count,
  871.                   panel->reverse, panel->case_sensitive, panel->filter);
  872.     panel->marked = 0;
  873.     panel->total  = 0;
  874.     panel->has_dir_sizes = 0;
  875.     
  876.     for (i = 0; i < panel->count; i++)
  877.     if (panel->dir.list [i].f.marked){
  878.         panel->marked++;
  879.         panel->total += panel->dir.list [i].buf.st_size;
  880.     }
  881. }
  882.  
  883. void paint_frame (WPanel *panel)
  884. {
  885. #ifndef HAVE_X
  886.     int  header_len;
  887.     int  spaces, extra;
  888.     int  i, top, side, width;
  889.     char *txt, buffer[30]; /*Hope that this is enough ;-) */
  890.  
  891.     if (!panel->split)
  892.     adjust_top_file (panel);
  893.     
  894.     widget_erase (&panel->widget);
  895.     show_dir (panel);
  896.  
  897.     widget_move (&panel->widget, 1, 1);
  898.  
  899.     for (side = 0; side <= panel->split; side++){
  900.     if (side){
  901.         set_attr (0, 0);
  902.         one_vline ();
  903.         width = panel->widget.cols - panel->widget.cols/2 - 1;
  904.     } else if (panel->split)
  905.         width = panel->widget.cols/2 - 3;
  906.     else
  907.         width = panel->widget.cols - 2;
  908.     
  909.     for (i = 0, top = panel->fmt_count; i < top; i++){
  910.  
  911.         if (panel->format [i].string_fn){
  912.         txt = panel->format [i].title;
  913.         header_len = strlen (txt);
  914.         if (header_len > panel->format [i].field_len){
  915.             strcpy (buffer, txt);
  916.             txt = buffer;
  917.             txt [panel->format [i].field_len] = 0;
  918.             header_len = strlen (txt);
  919.         }
  920.         
  921.         set_attr (0, 1);
  922.         spaces = (panel->format [i].field_len - header_len) / 2;
  923.         extra  = (panel->format [i].field_len - header_len) % 2;
  924.         printw ("%*s%-s%*s", spaces, "",
  925.              txt, spaces+extra, "");
  926.         width -= 2 * spaces + extra + header_len;
  927.         } else {
  928.         set_attr (0, 0);
  929.         one_vline ();
  930.         width --;
  931.         continue;
  932.         }
  933.     }
  934.     if (width > 0)
  935.         printw ("%*s", width, "");
  936.     }
  937. #else
  938.     show_dir (panel);
  939. #endif
  940. }
  941.  
  942. static char *parse_panel_size (WPanel *panel, char *format)
  943. {
  944.     format = skip_separators (format);
  945.  
  946.     panel->frame_size = frame_half;
  947.     panel->split = 0;
  948.     
  949.     if (strncmp (format, "full", 4) == 0){
  950.     panel->frame_size = frame_full;
  951.     format += 4;
  952.     } else if (strncmp (format, "half", 4) == 0){
  953.     format += 4;
  954.     }
  955.     panel_update_cols (&(panel->widget), panel->frame_size);
  956.     
  957.     /* Now, the optional column specifier */
  958.     format = skip_separators (format);
  959.     
  960.     if (*format == '1' || *format == '2'){
  961.     panel->split = *format == '2';
  962.     format++;
  963.     }
  964.  
  965.     if (horizontal_split)
  966.     panel->widget.cols = COLS;
  967.     
  968.     return skip_separators (format);
  969. }
  970.  
  971. /* Format is:
  972.  
  973.    all              := panel_format? format
  974.    panel_format     := [full|half] [1|2]
  975.    format           := one_format_e
  976.                      | format , one_format_e
  977.  
  978.    one_format_e     := just format.id [opt_size]
  979.    just             := [<|>]
  980.    opt_size         := : size [opt_expand]
  981.    size             := [0-9]+
  982.    opt_expand       := +
  983.    
  984. */
  985.  
  986. format_e *parse_display_format (WPanel *panel, char *format, 
  987.                 char **error, int isstatus)
  988. {
  989. #define MAX_EXPAND 4
  990.     
  991.     format_e *darr;        /* The formats we return */
  992.     int  fields;        /* Number of fields */
  993.     int  expand_list [MAX_EXPAND]; /* Expand at most 4 fields. */
  994.     int  expand_top = 0;    /* Max used element in expand */
  995.     int  field;
  996.     int  usable_columns;    /* Usable columns in the panel */
  997.     int  total_cols = 0;    /* Used columns by the format */
  998.     char *s;
  999.     int  i, j;
  1000.     int  set_justify;        /* flag: set justification mode? */
  1001.     int  justify = 0;        /* Which mode. */
  1002.     int  cols_save;
  1003.  
  1004.     *error = 0;
  1005.     
  1006.     if (!format)
  1007.     format = "half type,name,|,size,|,perm";
  1008.  
  1009.     /* Determine the panel size */
  1010.     cols_save = panel->widget.cols;
  1011.     format = parse_panel_size (panel, format);
  1012.     
  1013.     /* This makes sure that the panel and mini status full/half mode
  1014.        setting is equal */
  1015.     if (isstatus){
  1016.         panel->widget.cols = cols_save;
  1017.     }
  1018.  
  1019.     usable_columns = ((panel->widget.cols-2)/(panel->split+1)) - panel->split;
  1020.     
  1021.     /* Count the number of fields */
  1022.     fields = 1;
  1023.     for (s = format; *s; s++)
  1024.     if (*s == ',')
  1025.         fields++;
  1026.  
  1027.     panel->fmt_count = fields;
  1028.     
  1029.     /* Allocate the space */
  1030.     darr = xmalloc (sizeof (format_e) * fields, "parse_display_format");
  1031.     
  1032.     for (field = 0; field < fields; field++){
  1033.     int found = 0;
  1034.     int expands = 1;
  1035.  
  1036.     format = skip_separators (format);
  1037.  
  1038.     if (*format == '<' || *format == '>'){
  1039.         set_justify = 1;
  1040.         justify = *format == '<' ? J_LEFT : J_RIGHT;
  1041.         format = skip_separators (format+1);
  1042.     } else
  1043.         set_justify = 0;
  1044.     
  1045.     for (i = 0; i < ELEMENTS(formats); i++){
  1046.         int klen = strlen (formats [i].id);
  1047.  
  1048.         if (strncmp (format, formats [i].id, klen) != 0)
  1049.         continue;
  1050.  
  1051.         format += klen;
  1052.  
  1053.         darr [field].field_len = formats [i].min_size;
  1054.         darr [field].string_fn = formats [i].string_fn;
  1055.         darr [field].title     = formats [i].title;
  1056.  
  1057.         if (set_justify)
  1058.         darr [field].just_mode = justify;
  1059.         else
  1060.         darr [field].just_mode = formats [i].default_just;
  1061.  
  1062.         found = 1;
  1063.  
  1064.         format = skip_separators (format);
  1065.  
  1066.         /* If we have a size specifier */
  1067.         if (*format == ':'){
  1068.         int req_length;
  1069.  
  1070.         /* If the size was specified, we don't want
  1071.          * auto-expansion by default
  1072.          */
  1073.         expands = 0;
  1074.         format++;
  1075.         req_length = atoi (format);
  1076. #if 0        
  1077.         if (req_length > darr [field].field_len)
  1078. #endif
  1079.             darr [field].field_len = req_length;
  1080.  
  1081.         format = skip_numbers (format);
  1082.  
  1083.         /* Now, if they insist on expansion */
  1084.         if (*format == '+')
  1085.             expands = 1;
  1086.         format++;
  1087.         }
  1088.  
  1089.         if (expands) {
  1090.         /* Take note if it's expandable */
  1091.         if (formats [i].expands && expand_top < MAX_EXPAND)
  1092.             expand_list [expand_top++] = field;
  1093.         }
  1094.         break;
  1095.     }
  1096.     if (!found){
  1097.         char old_char;
  1098.         
  1099.         int pos = min (8, strlen (format));
  1100.         free (darr);
  1101.         old_char = format [pos];
  1102.         format [pos] = 0;
  1103.         *error = copy_strings("Unknow tag on display format: ", format, 0);
  1104.         format [pos] = old_char;
  1105.         return 0;
  1106.     }
  1107.     total_cols += darr [field].field_len;
  1108.  
  1109.     }
  1110.     
  1111.     /* If we used more columns than the available columns, adjust that */
  1112.     if (total_cols > usable_columns){
  1113.     int dif   = total_cols - usable_columns;
  1114.     
  1115.     while (dif)
  1116.         for (j = 0; j < field; j++){
  1117.         if (darr [j].field_len-1){
  1118.             darr [j].field_len--;
  1119.             if (dif)
  1120.             dif--;
  1121.         }
  1122.         }
  1123.     total_cols = usable_columns;
  1124.     }
  1125.  
  1126.     /* Expand the available space */
  1127.     if ((usable_columns > total_cols) && expand_top){
  1128.     int spaces = (usable_columns - total_cols) / expand_top;
  1129.     int extra  = (usable_columns - total_cols) % expand_top;
  1130.     
  1131.     for (i = 0; i < expand_top; i++)
  1132.         darr [expand_list [i]].field_len += spaces;
  1133.  
  1134.     /* The modulo goes to the first one */
  1135.     darr [expand_list [0]].field_len += extra;
  1136.     }
  1137.     
  1138.     return darr;
  1139. }
  1140.  
  1141. /* Switches the panel to the mode specified in the format */
  1142. char *set_panel_format (WPanel *p, char *format)
  1143. {
  1144.     char *err;
  1145.  
  1146.     if (p->format)
  1147.     free (p->format);
  1148.     
  1149.     p->format = parse_display_format (p, format, &err, 0);
  1150.     if (err)
  1151.     return err;
  1152.  
  1153.     panel_update_cols (&(p->widget), p->frame_size);
  1154.     paint_frame (p);
  1155.     paint_panel (p);
  1156.     
  1157.     return 0;
  1158. }
  1159.  
  1160. /* Given the panel->view_type returns the format string to be parsed */
  1161. char *panel_format (WPanel *panel)
  1162. {
  1163.     switch (panel->list_type){
  1164.  
  1165.     case list_long:
  1166.     return "full perm,space,nlink,space,owner,space,group,space,size,space,mtime,space,name";
  1167.  
  1168.     case list_brief:
  1169.     return "half 2,type,name";
  1170.  
  1171.  
  1172.     case list_user:
  1173.     return panel->user_format;
  1174.  
  1175.     default:
  1176.     case list_full:
  1177.     return "half type,name,|,size,|,mtime";
  1178.     }
  1179. }
  1180.  
  1181. /*                          */
  1182. /* Panel operation commands */
  1183. /*                          */
  1184.  
  1185. /* Returns the number of items in the given panel */
  1186. int ITEMS (WPanel *p)
  1187. {
  1188. #ifdef HAVE_TK
  1189.     return p->widget.lines;
  1190. #else
  1191.     if (p->split)
  1192.     return llines (p) * 2;
  1193.     else
  1194.     return llines (p);
  1195. #endif
  1196. }
  1197.  
  1198. /* This function sets redisplays the selection */
  1199. void select_item (WPanel *panel)
  1200. {
  1201.     int repaint = 0;
  1202.     int items = ITEMS (panel);
  1203.     
  1204.     /* Although currently all over the code we set the selection and
  1205.        top file to decent values before calling select_item, I could
  1206.        forget it someday, so it's better to do the actual fitting here */
  1207.  
  1208. #ifdef HAVE_X
  1209.     int old_top;
  1210.     old_top = panel->top_file;
  1211. #endif
  1212.     
  1213.     if (panel->top_file < 0){
  1214.     repaint = 1;
  1215.     panel->top_file = 0;
  1216.     }
  1217.  
  1218.     if (panel->selected < 0)
  1219.     panel->selected = 0;
  1220.  
  1221.     if (panel->selected > panel->count-1)
  1222.     panel->selected = panel->count - 1;
  1223.  
  1224.     if (panel->top_file > panel->count-1){
  1225.     repaint = 1;
  1226.     panel->top_file = panel->count-1;
  1227.     }
  1228.     
  1229.     if ((panel->count - panel->top_file) < items){
  1230.     repaint = 1;
  1231.     panel->top_file = panel->count - items;
  1232.     if (panel->top_file < 0)
  1233.         panel->top_file = 0;
  1234.     }
  1235.     
  1236.     if (panel->selected < panel->top_file){
  1237.     repaint = 1;
  1238.     panel->top_file = panel->selected;
  1239.     }
  1240.  
  1241.     if ((panel->selected - panel->top_file) >= items){
  1242.     repaint = 1;
  1243.     panel->top_file = panel->selected - items + 1;
  1244.     }
  1245.  
  1246. #ifndef HAVE_X    
  1247.     set_attr (1, selection (panel)->f.marked);
  1248.     if (repaint)
  1249.     paint_panel (panel);
  1250.     else
  1251.     repaint_file (panel, panel->selected, 1);
  1252. #else
  1253.     if (old_top != panel->top_file)
  1254.     x_adjust_top_file (panel);
  1255.     x_select_item (panel);
  1256. #endif
  1257.  
  1258.     display_mini_info (panel);
  1259.  
  1260.     execute_hooks (select_file_hook);
  1261. }
  1262.  
  1263. /* Clears all files in the panel, used only when one file was marked */
  1264. void unmark_files (WPanel *panel)
  1265. {
  1266.     int i;
  1267.  
  1268.     if (!panel->marked)
  1269.     return;
  1270.     for (i = 0; i < panel->count; i++)
  1271.     file_mark (panel, i, 0);
  1272.  
  1273.     panel->dirs_marked = 0;
  1274.     panel->marked = 0;
  1275.     panel->total = 0;
  1276. }
  1277.  
  1278. void unselect_item (WPanel *panel)
  1279. {
  1280. #ifndef HAVE_X
  1281.     set_attr (0, selection (panel)->f.marked);
  1282.     repaint_file (panel, panel->selected, 1);
  1283. #else
  1284.     x_unselect_item (panel);
  1285. #endif
  1286. }
  1287.  
  1288. /*                           */
  1289. /* Panel key binded commands */
  1290. /*                           */
  1291. static void move_down (WPanel *panel)
  1292. {
  1293.     if (panel->selected+1 == panel->count)
  1294.     return;
  1295.     
  1296.     unselect_item (panel);
  1297.     panel->selected++;
  1298.  
  1299. #ifndef HAVE_X
  1300.     if (panel->selected - panel->top_file == ITEMS (panel) &&
  1301.     panel_scroll_pages){
  1302.     /* Scroll window half screen */
  1303.     panel->top_file += ITEMS (panel)/2;
  1304.     if (panel->top_file > panel->count - ITEMS (panel))
  1305.         panel->top_file = panel->count - ITEMS (panel);
  1306.     paint_dir (panel);
  1307.     select_item (panel);
  1308.     }
  1309. #endif
  1310.     select_item (panel);
  1311. }
  1312.  
  1313. static void move_up (WPanel *panel)
  1314. {
  1315.     if (panel->selected == 0)
  1316.     return;
  1317.  
  1318.     unselect_item (panel);
  1319.     panel->selected--;
  1320. #ifndef HAVE_X
  1321.     if (panel->selected < panel->top_file && panel_scroll_pages){
  1322.     /* Scroll window half screen */
  1323.     panel->top_file -= ITEMS (panel)/2;
  1324.     if (panel->top_file < 0) panel->top_file = 0;
  1325.     paint_dir (panel);
  1326.     }
  1327. #endif
  1328.     select_item (panel);
  1329. }
  1330.  
  1331.  
  1332. /* Changes the selection by lines (may be negative) */
  1333. static void move_selection (WPanel *panel, int lines)
  1334. {
  1335.     int new_pos;
  1336.     int adjust = 0;
  1337.  
  1338.     new_pos = panel->selected + lines;
  1339.     if (new_pos >= panel->count)
  1340.     new_pos = panel->count-1;
  1341.  
  1342.     if (new_pos < 0)
  1343.     new_pos = 0;
  1344.  
  1345.     unselect_item (panel);
  1346.     panel->selected = new_pos;
  1347.  
  1348. #ifndef HAVE_X
  1349.     if (panel->selected - panel->top_file >= ITEMS (panel)){
  1350.     panel->top_file += lines;
  1351.     adjust = 1;
  1352.     }
  1353.     
  1354.     if (panel->selected - panel->top_file < 0){
  1355.     panel->top_file += lines;
  1356.     adjust = 1;
  1357.     }
  1358.     
  1359.     if (adjust){
  1360.     if (panel->top_file > panel->selected)
  1361.         panel->top_file = panel->selected;
  1362.     if (panel->top_file < 0)
  1363.         panel->top_file = 0;
  1364.     paint_dir (panel);
  1365.     }
  1366. #endif
  1367.     select_item (panel);
  1368. }
  1369.  
  1370. static int move_left (WPanel *panel, int c_code)
  1371. {
  1372.     if (panel->split){
  1373.     move_selection (panel, -llines (panel));
  1374.     return 1;
  1375.     } else 
  1376.     return maybe_cd (c_code, 0);
  1377. }
  1378.  
  1379. static int move_right (WPanel *panel, int c_code)
  1380. {
  1381.     if (panel->split){
  1382.     move_selection (panel, llines (panel));
  1383.     return 1;
  1384.     } else
  1385.     return maybe_cd (c_code, 1);
  1386. }
  1387.  
  1388. static void prev_page (WPanel *panel)
  1389. {
  1390.     int items;
  1391.  
  1392.     if (!panel->selected && !panel->top_file)
  1393.         return;
  1394.     unselect_item (panel);
  1395.     items = ITEMS (panel);
  1396.     if (panel->top_file < items)
  1397.         items = panel->top_file;
  1398.     if (!items)
  1399.         panel->selected = 0;
  1400.     else
  1401.         panel->selected -= items;
  1402.     panel->top_file -= items;
  1403.  
  1404.     /* This keeps the selection in a reasonable place */
  1405.     if (panel->selected < 0)
  1406.     panel->selected = 0;
  1407.     if (panel->top_file < 0)
  1408.     panel->top_file = 0;
  1409.     x_adjust_top_file (panel);
  1410.     select_item (panel);
  1411. #ifndef HAVE_X
  1412.     paint_dir (panel);
  1413. #endif
  1414. }
  1415.  
  1416. static void prev_page_key (WPanel *panel)
  1417. {
  1418.     if (console_flag && ctrl_pressed ()){
  1419.     do_cd ("..");
  1420.     } else
  1421.     prev_page (panel);
  1422. }
  1423.  
  1424. static void next_page (WPanel *panel)
  1425. {
  1426.     int items;
  1427.  
  1428.     if (panel->selected == panel->count - 1)
  1429.         return;
  1430.     unselect_item (panel);
  1431.     items = ITEMS (panel);
  1432.     if (panel->top_file > panel->count - 2 * items)
  1433.         items = panel->count - items - panel->top_file;
  1434.     if (panel->top_file + items < 0)
  1435.         items = - panel->top_file;
  1436.     if (!items)
  1437.         panel->selected = panel->count - 1;
  1438.     else
  1439.         panel->selected += items;
  1440.     panel->top_file += items;
  1441.  
  1442.     /* This keeps the selection in it's relative position */
  1443.     if (panel->selected >= panel->count)
  1444.     panel->selected = panel->count - 1;
  1445.     if (panel->top_file >= panel->count)
  1446.     panel->top_file = panel->count - 1;
  1447.     x_adjust_top_file (panel);
  1448.     select_item (panel);
  1449. #ifndef HAVE_X
  1450.     paint_dir (panel);
  1451. #endif
  1452. }
  1453.  
  1454. static void next_page_key (WPanel *panel)
  1455. {
  1456.     if (console_flag&&ctrl_pressed()&&
  1457.     (S_ISDIR(selection (panel)->buf.st_mode) ||
  1458.      link_isdir (selection (panel))))
  1459.         do_cd (selection (panel)->fname);
  1460.     else
  1461.     next_page (panel);
  1462. }
  1463.  
  1464. static void goto_top_file (WPanel *panel)
  1465. {
  1466.     unselect_item (panel);
  1467.     panel->selected = panel->top_file;
  1468.     select_item (panel);
  1469. }
  1470.  
  1471. static void goto_middle_file (WPanel *panel)
  1472. {
  1473.     unselect_item (panel);
  1474.     panel->selected = panel->top_file + (ITEMS (panel)/2);
  1475.     if (panel->selected >= panel->count)
  1476.     panel->selected = panel->count - 1;
  1477.     select_item (panel);
  1478. }
  1479.  
  1480. static void goto_bottom_file (WPanel *panel)
  1481. {
  1482.     unselect_item (panel);
  1483.     panel->selected = panel->top_file + ITEMS (panel)-1;
  1484.     if (panel->selected >= panel->count)
  1485.     panel->selected = panel->count - 1;
  1486.     select_item (panel);
  1487. }
  1488.  
  1489. static void move_home (WPanel *panel)
  1490. {
  1491.     if (panel->selected == 0)
  1492.     return;
  1493.     unselect_item (panel);
  1494.     
  1495.     if (torben_fj_mode){
  1496.     int middle_pos = panel->top_file + (ITEMS (panel)/2);
  1497.  
  1498.     if (panel->selected > middle_pos){
  1499.         goto_middle_file (panel);
  1500.         return;
  1501.     }
  1502.     if (panel->selected != panel->top_file){
  1503.         goto_top_file (panel);
  1504.         return;
  1505.     }
  1506.     }
  1507.     
  1508.     panel->top_file = 0;
  1509.     panel->selected = 0;
  1510.  
  1511. #ifndef HAVE_X
  1512.     paint_dir (panel);
  1513. #endif
  1514.     select_item (panel);
  1515. }
  1516.  
  1517. static void move_end (WPanel *panel)
  1518. {
  1519.     if (panel->selected == panel->count-1)
  1520.     return;
  1521.     unselect_item (panel);
  1522.     if (torben_fj_mode){
  1523.     int middle_pos = panel->top_file + (ITEMS (panel)/2);
  1524.  
  1525.     if (panel->selected < middle_pos){
  1526.         goto_middle_file (panel);
  1527.         return;
  1528.     }
  1529.     if (panel->selected != (panel->top_file + ITEMS(panel)-1)){
  1530.         goto_bottom_file (panel);
  1531.         return;
  1532.     }
  1533.     }
  1534.     
  1535.     panel->selected = panel->count-1;
  1536. #ifndef HAVE_X
  1537.     paint_dir (panel);
  1538. #endif
  1539.     select_item (panel);
  1540. }
  1541.  
  1542. /* This routine marks a file or a directory */
  1543. void do_file_mark (WPanel *panel, int idx, int mark)
  1544. {
  1545.     if (panel->dir.list [idx].f.marked == mark)
  1546.         return;
  1547.     /*
  1548.      * Only '..' can't be marked, '.' isn't visible.
  1549.      */
  1550.     if (strcmp (panel->dir.list [idx].fname, "..")){
  1551.     file_mark (panel, idx, mark);
  1552. #ifndef HAVE_XVIEW    
  1553.         set_attr  (1, panel->dir.list [idx].f.marked);
  1554.         repaint_file (panel, idx, 1);
  1555. #endif        
  1556.         if (panel->dir.list [idx].f.marked){
  1557.             panel->marked++;
  1558.             if (S_ISDIR (panel->dir.list [idx].buf.st_mode)) {
  1559.         if (panel->has_dir_sizes)
  1560.             panel->total += panel->dir.list [idx].buf.st_size;
  1561.                 panel->dirs_marked++;
  1562.         } else 
  1563.         panel->total += panel->dir.list [idx].buf.st_size;
  1564. #ifndef HAVE_XVIEW            
  1565.             set_colors (panel);
  1566. #endif
  1567.         } else {
  1568.             if (S_ISDIR(panel->dir.list [idx].buf.st_mode)) {
  1569.         if (panel->has_dir_sizes)
  1570.             panel->total -= panel->dir.list [idx].buf.st_size;
  1571.                 panel->dirs_marked--;
  1572.         } else
  1573.         panel->total -= panel->dir.list [idx].buf.st_size;
  1574.             panel->marked--;
  1575.         }
  1576.     }
  1577. }
  1578.  
  1579. static void do_mark_file (WPanel *panel, int do_move)
  1580. {
  1581.     do_file_mark (panel, panel->selected, selection (panel)->f.marked ? 0 : 1);
  1582.     if (mark_moves_down && do_move)
  1583.     move_down (panel);
  1584.     display_mini_info (panel);
  1585. }
  1586.  
  1587. static void mark_file (WPanel *panel)
  1588. {
  1589.     do_mark_file (panel, 1);
  1590. }
  1591.  
  1592. /* Incremental search of a file name in the panel */
  1593. static void do_search (WPanel *panel, int c_code)
  1594. {
  1595.     int l, i;
  1596.     int wrapped = 0;
  1597.     int found;
  1598.  
  1599.     l = strlen (panel->search_buffer);
  1600.     if (l && (c_code == 8 || c_code == 0177 || c_code == KEY_BACKSPACE))
  1601.     panel->search_buffer [--l] = 0;
  1602.     else {
  1603.     if (c_code && l < sizeof (panel->search_buffer)){
  1604.         panel->search_buffer [l] = c_code;
  1605.         panel->search_buffer [l+1] = 0;
  1606.         l++;
  1607.     }
  1608.     }
  1609.  
  1610.     found = 0;
  1611.     for (i = panel->selected; !wrapped || i != panel->selected; i++){
  1612.     if (i >= panel->count){
  1613.         i = 0;
  1614.         if (wrapped)
  1615.         break;
  1616.         wrapped = 1;
  1617.     }
  1618.     if (strncmp (panel->dir.list [i].fname, panel->search_buffer, l) == 0){
  1619.         panel->selected = i;
  1620. #if 0
  1621.         panel->top_file = panel->selected - panel->lines/2; 
  1622. #endif
  1623.         select_item (panel);
  1624.         found = 1;
  1625.         break;
  1626.     }
  1627.     }
  1628.     if (!found)
  1629.     panel->search_buffer [--l] = 0;
  1630. #ifndef HAVE_X    
  1631.     paint_panel (panel);
  1632. #endif
  1633. }
  1634.  
  1635. static void start_search (WPanel *panel)
  1636. {
  1637.     if (panel->searching){
  1638.     move_down (panel);
  1639.     do_search (panel, 0);
  1640.     } else {
  1641.     panel->searching = 1;
  1642.     panel->search_buffer [0] = 0;
  1643.     display_mini_info (panel);
  1644. #ifndef HAVE_X
  1645.     refresh ();
  1646. #endif
  1647.     }
  1648. }
  1649.  
  1650. void do_enter (WPanel *panel)
  1651. {
  1652.     if (S_ISDIR (selection (panel)->buf.st_mode)
  1653.     || link_isdir (selection (panel))){
  1654.     do_cd (selection (panel)->fname);
  1655.     } else { 
  1656.     if (is_exe (selection (panel)->buf.st_mode) &&
  1657.         if_link_is_exe (selection (panel))) {
  1658.         if (vfs_current_is_local ()) {
  1659. #ifdef _OS_NT
  1660.             char *tmp = copy_strings (".\\", selection (panel)->fname, 0);
  1661. #else
  1662.             char *tmp = copy_strings ("./", selection (panel)->fname, 0);
  1663. #endif
  1664.             execute (tmp);
  1665.             free (tmp);
  1666.         } else if (vfs_current_is_extfs ()) {
  1667.             char *tmp = vfs_get_current_dir();
  1668.             char *tmp2;
  1669.             if (tmp [strlen (tmp) - 1] != '/')
  1670.                 tmp2 = copy_strings (tmp, "/", selection (panel)->fname, 0);
  1671.             else
  1672.                 tmp2 = copy_strings (tmp, selection (panel)->fname, 0);
  1673.             extfs_run(tmp2);
  1674.             free (tmp2);
  1675.         }
  1676.         return;
  1677.     } else
  1678.         regex_command (selection (panel)->fname, "Open", NULL, 0);
  1679.     }
  1680. }
  1681.  
  1682. static void chdir_other_panel (WPanel *panel)
  1683. {
  1684.     char *new_dir;
  1685.  
  1686.     if (get_other_type () != view_listing)
  1687.     return;
  1688.  
  1689.     if (!S_ISDIR (cpanel->dir.list [cpanel->selected].buf.st_mode))
  1690.     new_dir = copy_strings (cpanel->cwd, PATH_SEP_STR "..", 0);
  1691.     else
  1692.     new_dir = copy_strings (cpanel->cwd, PATH_SEP_STR,
  1693.                 cpanel->dir.list [cpanel->selected].fname, 0);
  1694.  
  1695.     change_panel ();
  1696.     do_cd (new_dir);
  1697.     change_panel ();
  1698.  
  1699.     move_down (panel);
  1700.     
  1701.     free (new_dir);
  1702. }
  1703.  
  1704. static void chdir_to_readlink (WPanel *panel)
  1705. {
  1706.     char *new_dir;
  1707.  
  1708.     if (get_other_type () != view_listing)
  1709.     return;
  1710.  
  1711.     if (S_ISLNK (cpanel->dir.list [cpanel->selected].buf.st_mode)) {
  1712.     char buffer [MC_MAXPATHLEN], *p;
  1713.     int i;
  1714.     struct stat mybuf;
  1715.     
  1716.     i = readlink (selection (cpanel)->fname, buffer, MC_MAXPATHLEN);
  1717.     if (i < 0)
  1718.         return;
  1719.     if (mc_stat (selection (cpanel)->fname, &mybuf) < 0)
  1720.         return;
  1721.     buffer [i] = 0;
  1722.     if (!S_ISDIR (mybuf.st_mode)) {
  1723.         p = strrchr (buffer, PATH_SEP);
  1724.         if (p && !p[1]) {
  1725.         *p = 0;
  1726.         p = strrchr (buffer, PATH_SEP);
  1727.         }
  1728.         if (!p)
  1729.             return;
  1730.         p[1] = 0;
  1731.     }
  1732.     if (*buffer == PATH_SEP) {
  1733.         new_dir = strdup (buffer);
  1734.     } else {
  1735.         if (cpanel->cwd [strlen (cpanel->cwd) - 1] == PATH_SEP)
  1736.             new_dir = copy_strings (cpanel->cwd, buffer, 0);
  1737.         else
  1738.             new_dir = copy_strings (cpanel->cwd, PATH_SEP_STR, buffer, 0);
  1739.     }
  1740.  
  1741.     change_panel ();
  1742.     do_cd (new_dir);
  1743.     change_panel ();
  1744.     
  1745.     move_down (panel);
  1746.         
  1747.     free (new_dir);
  1748.     }
  1749. }
  1750.  
  1751. static key_map panel_keymap [] = {
  1752.     { KEY_DOWN,   move_down },
  1753.     { KEY_UP,     move_up },
  1754.  
  1755.     /* The action button :-) */
  1756.     { '\n',       do_enter },
  1757.     { KEY_ENTER,  do_enter },
  1758.  
  1759.     { KEY_IC,     mark_file },
  1760.     { KEY_HOME,      move_home },
  1761.     { KEY_C1,     move_end },
  1762.     { KEY_END,    move_end },
  1763.     { KEY_A1,     move_home },
  1764.     { KEY_NPAGE,  next_page_key },
  1765.     { KEY_PPAGE,  prev_page_key },
  1766.  
  1767.     /* To quickly move in the panel */
  1768.     { ALT('g'),   goto_top_file },
  1769.     { ALT('h'),   goto_middle_file },
  1770.     { ALT('r'),   goto_middle_file }, /* M-r like emacs */
  1771.     { ALT('j'),   goto_bottom_file },
  1772.  
  1773.     /* Emacs-like bindings */
  1774.     { XCTRL('v'), next_page },        /* C-v like emacs */
  1775.     { ALT('v'),   prev_page },        /* M-v like emacs */
  1776.     { XCTRL('p'), move_up },        /* C-p like emacs */
  1777.     { XCTRL('n'), move_down },        /* C-n like emacs */
  1778.     { XCTRL('s'), start_search },    /* C-s like emacs */
  1779.     { ALT('s'),   start_search },    /* M-s not like emacs */
  1780.  
  1781.     /* The functions keys we deal with */
  1782.     { KEY_F(3),   view_cmd },
  1783.     { KEY_F(13),  view_simple_cmd },
  1784.     { KEY_F(4),   edit_cmd },
  1785.     { KEY_F(5),   copy_cmd },
  1786.     { KEY_F(6),   ren_cmd },
  1787.     { KEY_F(7),   mkdir_cmd },
  1788.     { KEY_F(8),   delete_cmd },
  1789.     
  1790.     { XCTRL('t'), mark_file },
  1791.     { ALT('o'),   chdir_other_panel },
  1792.     { ALT('l'),   chdir_to_readlink },
  1793.     { 0, 0 }
  1794. };
  1795.     
  1796. static inline int panel_key (WPanel *panel, int key)
  1797. {
  1798.     int i;
  1799.  
  1800.     for (i = 0; panel_keymap [i].key_code; i++){
  1801.     if (key == panel_keymap [i].key_code){
  1802.         panel->searching = 0;
  1803.         (*panel_keymap [i].fn)(panel);
  1804.         return 1;
  1805.     }
  1806.     }
  1807.     /* We do not want to take a key press if nothing can be done with it */
  1808.     /* The command line widget may do something more usefull */
  1809.     if (key == KEY_LEFT)
  1810.     return move_left (panel, key);
  1811.  
  1812.     if (key == KEY_RIGHT)
  1813.     move_right (panel, key);
  1814.  
  1815.     if (panel->searching){
  1816.     do_search (panel, key);
  1817.     return 1;
  1818.     }
  1819.     if (!command_prompt)
  1820.     start_search (panel);
  1821.     if (key == -1)
  1822.     return 0;
  1823.     
  1824.     if (panel_keymap [i].key_code == 0){
  1825.     if (panel->searching){
  1826.         panel->searching = 0;
  1827.         display_mini_info (panel);
  1828.     }
  1829.     return 0;
  1830.     }
  1831.     return 1;
  1832. }
  1833.  
  1834. int panel_callback (Dlg_head *h, WPanel *panel, int msg, int par)
  1835. {
  1836.     switch (msg){
  1837.     case WIDGET_INIT:
  1838. #ifdef HAVE_X
  1839.     define_label (h, (Widget *)panel, 2, "Menu", user_menu_cmd);
  1840.     define_label (h, (Widget *)panel, 3, "View", view_panel_cmd);
  1841.     define_label (h, (Widget *)panel, 4, "Edit", edit_panel_cmd);
  1842.     define_label (h, (Widget *)panel, 5, "Copy", copy_cmd);
  1843.     define_label (h, (Widget *)panel, 6, "RenMov", ren_cmd);
  1844.     define_label (h, (Widget *)panel, 7, "Mkdir", mkdir_panel_cmd);
  1845.     define_label (h, (Widget *)panel, 8, "Delete", delete_cmd);
  1846.     x_create_panel (h, h->wdata, panel);
  1847. #endif    
  1848.     return 1;
  1849.     
  1850.     case WIDGET_DRAW:
  1851. #ifndef HAVE_XVIEW    
  1852.     paint_panel (panel);
  1853. #else
  1854.     show_dir (panel);    
  1855. #endif
  1856.     break;
  1857.  
  1858.     case WIDGET_FOCUS:
  1859.     cpanel = panel;
  1860.     panel->active = 1;
  1861.     if (mc_chdir (panel->cwd) != 0){
  1862.         message (1, " Error ", " Can't chdir to %s \n %s ",
  1863.              panel->cwd, unix_error_string (errno));
  1864.     } else
  1865.         subshell_chdir (panel->cwd);
  1866.         
  1867.     show_dir (panel);
  1868.     select_item (panel);
  1869. #ifndef HAVE_X    
  1870.     define_label (h, (Widget *)panel, 2, "Menu", user_menu_cmd);
  1871.     define_label (h, (Widget *)panel, 3, "View", view_panel_cmd);
  1872.     define_label (h, (Widget *)panel, 4, "Edit", edit_panel_cmd);
  1873.     define_label (h, (Widget *)panel, 5, "Copy", copy_cmd);
  1874.     define_label (h, (Widget *)panel, 6, "RenMov", ren_cmd);
  1875.     define_label (h, (Widget *)panel, 7, "Mkdir", mkdir_panel_cmd);
  1876.     define_label (h, (Widget *)panel, 8, "Delete", delete_cmd);
  1877.     redraw_labels (h, (Widget *)panel);
  1878. #endif
  1879.     return 1;
  1880.     
  1881.     case WIDGET_UNFOCUS:
  1882.     /* Janne: look at this for the multiple panel options */
  1883.     panel->active = 0;
  1884.     if (panel->searching){
  1885.         panel->searching = 0;
  1886.         display_mini_info (panel);
  1887.     }
  1888.     show_dir (panel);
  1889.     unselect_item (panel);
  1890.     return 1;
  1891.     
  1892.     case WIDGET_KEY:
  1893.     return panel_key (panel, par);
  1894.     break;
  1895.     }
  1896.     return default_proc (h, msg, par);
  1897. }
  1898.  
  1899. /*                                     */
  1900. /* Panel mouse events support routines */
  1901. /*                                     */
  1902. static int mouse_marking = 0;
  1903.  
  1904. static void mouse_toggle_mark (WPanel *panel)
  1905. {
  1906.     do_mark_file (panel, 0);
  1907.     mouse_marking = selection (panel)->f.marked;
  1908. }
  1909.  
  1910. static void mouse_set_mark (WPanel *panel)
  1911. {
  1912.     if (mouse_marking && !(selection (panel)->f.marked))
  1913.     do_mark_file (panel, 0);
  1914.     else if (!mouse_marking && (selection (panel)->f.marked))
  1915.     do_mark_file (panel, 0);
  1916. }
  1917.  
  1918. static inline int mark_if_marking (WPanel *panel, Gpm_Event *event)
  1919. {
  1920.     if (event->buttons & GPM_B_RIGHT){
  1921.     if (event->type & GPM_DOWN)
  1922.         mouse_toggle_mark (panel);
  1923.     else
  1924.         mouse_set_mark (panel);
  1925.     return 1;
  1926.     }
  1927.     return 0;
  1928. }
  1929.  
  1930. /* not static because it's called from Tk's version */
  1931. int panel_event (Gpm_Event *event, WPanel *panel)
  1932. {
  1933. #ifdef HAVE_X
  1934.     const int lines = panel->count;
  1935. #else
  1936.     const int lines = llines (panel);
  1937. #endif
  1938.     
  1939.     int my_index;
  1940.     extern void change_panel (void);
  1941.  
  1942.     event->y -= 2;
  1943.     if ((event->type & (GPM_DOWN|GPM_DRAG))){
  1944.  
  1945.     if (panel != (WPanel *) current_dlg->current->widget)
  1946.         change_panel ();
  1947.  
  1948.     if (event->y <= 0){
  1949.         mark_if_marking (panel, event);
  1950. #ifndef HAVE_X
  1951.         if (mouse_move_pages)
  1952.         prev_page (panel);
  1953.         else
  1954.         move_up (panel);
  1955. #endif
  1956.         return MOU_REPEAT;
  1957.     }
  1958.  
  1959.     if (!((panel->top_file + event->y <= panel->count) &&
  1960.           event->y <= lines)){
  1961.         mark_if_marking (panel, event);
  1962. #ifndef HAVE_X
  1963.         if (mouse_move_pages)
  1964.         next_page (panel);
  1965.         else
  1966.         move_down (panel);
  1967. #endif
  1968.         return MOU_REPEAT;
  1969.     }
  1970.     my_index = panel->top_file + event->y - 1;
  1971.     if (panel->split){
  1972.         if (event->x > ((panel->widget.cols-2)/2))
  1973.         my_index += llines (panel);
  1974.     }
  1975.  
  1976.     if (my_index >= panel->count)
  1977.         my_index = panel->count - 1;
  1978.     
  1979.     if (my_index != panel->selected){
  1980.         unselect_item (panel);
  1981.         panel->selected = my_index;
  1982.         select_item (panel);
  1983.     }
  1984.  
  1985.     /* This one is new */
  1986.     mark_if_marking (panel, event);
  1987.     
  1988.     } else if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
  1989.             if (event->y > 0 && event->y <= lines)
  1990.         do_enter (panel);
  1991.     }
  1992.     return MOU_NORMAL;
  1993. }
  1994.  
  1995. WPanel *get_other_panel (int line)
  1996. {
  1997.     if (get_other_type () != view_listing){
  1998.     fprintf (stderr, "Fatal: used opanel with view_type != listing\n\r");
  1999.     fprintf (stderr, "Report this error to mc-devel@nuclecu.unam.mx\n\r");
  2000.     fprintf (stderr, "Error line number: %d\n\r", line);
  2001.     exit (1);
  2002.     }
  2003.     return (WPanel *) get_panel_widget (get_other_index ());
  2004. }
  2005.  
  2006. void file_mark (WPanel *panel, int index, int val)
  2007. {
  2008.     panel->dir.list [index].f.marked = val;
  2009. #ifdef HAVE_X
  2010.     x_panel_select_item (panel, index, val);
  2011. #endif
  2012. }
  2013.